package lambdasinaction.chap6;

import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;

import static java.util.stream.Collector.Characteristics.CONCURRENT;
import static java.util.stream.Collector.Characteristics.IDENTITY_FINISH;

/**
 * Created by ThinkPad on 2017/8/21.
 * 理解Collector接口声明的方法
 */
public class ToListCollector<T> implements Collector<T,List<T>,List<T>> {
    /**
     * 建立新的结果容器:
     * supplier方法必须返回一个结果为空的supplier,在调用时它会创建一个空的累加器实例,供数据收集过程使用
     * @return
     */
    @Override
    public Supplier<List<T>> supplier() {
        return () -> new ArrayList<T>();
//        也可以这么写:return ArrayList::new;
    }

    /**
     * 将元素添加到结果容器
     * 有两个参数:保存归约结果的累加器(已收集了流中的前n-1个元素),还有第n个元素本身.
     * @return 执行归约操作的函数
     * 本例这个函数仅仅会把当前元素添加至已经遍历过的元素的列表
     */
    @Override
    public BiConsumer<List<T>, T> accumulator() {
        return (list,item) -> list.add(item);
//        也可以写成:return List::add;
    }

    /**
     * 合并两个结果容器
     * @return 供归约操作使用的函数,它定义了对流的各个子部分进行并行处理时,
     * 各个子部分归约所得的累加器要如何合并
     * 对于本例而言,这个方法的实现非常简单,只要把从流的第二个部分收集到的项目列表加到
     * 遍历第一部分时得到的列表后面就行了
     */
    @Override
    public BinaryOperator<List<T>> combiner() {
        return (list1,list2) -> {
            list1.addAll(list2);
            return list1;
        };
    }

    /**
     * 对结果容器应用最终转换
     * 在遍历完流后,finisher方法必须返回在积累过程的最后要调用的一个函数,以便将累加器对象转为整个集合操作的最终结果.
     * @return 最后要调用的函数
     * 本例累加器对象恰好符合预期的最终结果,因此无需进行转换,所以只需返回identity函数
     */
    @Override
    public Function<List<T>, List<T>> finisher() {
        return Function.identity();
    }

    /**
     *
     * @return 一个不可变的Characteristics集合,它定义了收集器的行为--尤其是关于流是否可以并行归约,
     * 以及可以使用那些优化的提示.
     * Characteristics是一个包含三个项目的枚举:
     * UNORDERED--归约结果不受流中项目的遍历和累积顺序的影响.
     * CONCURRENT--accumulator函数可以从多个线程同时调用,如果收集器没有标为UNORDERED
     *      ,那么它仅在用于无序数据源时才可以并行归约.
     * IDENTITY_FINISH--表明完成器方法返回的函数是一个恒等函数,可以跳过.
     *
     * 本例是IDENTITY_FINISH的,因为用来累积流中的元素的List已经是我们要的最终结果,用不着进一步转换了,
     * 但它不是UNORDERED,因为用在有序流上的时候,我们还希望顺序能够保留在得到的List中,最后,它是
     * CONCURRENT的,但刚刚说过了,仅仅在背后的数据源无序时才会并行处理
     */
    @Override
    public Set<Characteristics> characteristics() {
        return Collections.unmodifiableSet(EnumSet.of(
                IDENTITY_FINISH,CONCURRENT
        ));
    }
}
